package net.club.daos;


import net.club.hibernate.DataAccessLayerException;
import net.club.hibernate.HibernateFactory;
import net.club.hibernate.HibernateSessionFactory;

import org.apache.log4j.Logger;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author alarosa@technisys.net
  */
public abstract class AbstractDao {
    //~ Static fields/initializers -----------------------------------------------------------------

    private static final Logger logger = Logger.getLogger(AbstractDao.class);

    //~ Instance fields ----------------------------------------------------------------------------

    protected Session session;
    protected Transaction tx;

    //~ Constructors -------------------------------------------------------------------------------

    /**
     * Crea un nuevo objeto AbstractDao.
     */
    public AbstractDao() {
    	HibernateFactory.buildIfNeeded();
    }

    //~ Methods ------------------------------------------------------------------------------------

    /**
     * Documentacion pendiente.
     *
     * @param obj requerido.
     */
    protected boolean save(Object obj)throws DataAccessLayerException{
        boolean result=false;
    	try {
            startOperation();
            session.save(obj);
            tx.commit();
            result=true;
            if (logger.isDebugEnabled()) {
                logger.debug("save commit: " + obj);
            }
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
        return result;
    }
    /**
     * Documentacion pendiente.
     *
     * @param obj requerido.
     */
    protected boolean update(Object obj) {
        boolean result=false;
    	try {
            if (logger.isDebugEnabled()) {
                logger.debug("update: " + obj);
            }

            startOperation();
            session.update(obj);
            tx.commit();
            result=true;
            if (logger.isDebugEnabled()) {
                logger.debug("update commit: " + obj);
            }
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
        return result;
    }
    /**
     * Documentacion pendiente.
     *
     * @param obj requerido.
     */
    protected boolean delete(Object obj) {
        boolean result=false;
    	try {
            startOperation();
            session.delete(obj);
            tx.commit();
            result = true;
            if (logger.isDebugEnabled()) {
                logger.debug("delete: " + obj);
            }
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
        return result;
    }
    /**
     * Documentacion pendiente.
     *
     * @param clazz requerido.
     * @param id requerido.
     *
     * @return (documentacion pendiente).
     */
    @SuppressWarnings("unchecked")
    protected Object find(Class clazz, Integer id) {
        Object obj = null;
        try {
            startOperation();
            obj = session.load(clazz, id);
            tx.commit();
            if (logger.isDebugEnabled()) {
                logger.debug("find: " + obj);
            }
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
        return obj;
    }
    /**
     * @param from:   bean1 [alias1], bean 2[alias2],
     *                   beanN [aliasN](sin agregar from)
     * @param where:  (bean1|alias1].atributo [AND|OR|ETC..] (sin agregar where)
     * @param hashMap String: (a|d|s|i)n
     *                   Object:  el objeto asociado al parametro
     *                   ej: (AmbienteType,Date,String,Integer).
     * @return (List object) obtenidos por el HQL y los objetos que extienden del AbstractDao.
     */
    @SuppressWarnings("unchecked")
    protected List findQuery(String from, String where, Map<String, Object> hashMap) {
        List objects = new ArrayList();
        try {
            startOperation();
            Query query = session.createQuery(" from " + from + " where " + where);
            query = setQueryParameters(query, hashMap);

            if (logger.isDebugEnabled()) {
                logger.debug(query.getQueryString());
            }

            Iterator pairs = query.list().iterator();

            while (pairs.hasNext()) {
                Object[] pair = (Object[]) pairs.next();

                objects.add(pair[0]);
            }

            tx.commit();
            if (logger.isDebugEnabled()) {
                logger.debug("findQuery: " + from + where + "cantidad de registros: " +
                    objects.size());
            }
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
        return objects;
    }
    @SuppressWarnings({"unused", "unchecked"})
    private Query setQueryParameters(Query query, Map<String, Object> hashMap) {
        for (Iterator i = hashMap.entrySet().iterator(); i.hasNext();) {
            Map.Entry e = (Map.Entry) i.next();
            query.setParameter((String) e.getKey(),  e.getValue());
            
        }
        return query;
    }
    /**
     * @param clazz: clase bean.
     * @param where:  (bean1|alias1].atributo [AND|OR|ETC..] (sin agregar where)
     * @param hashMap String: (a|d|s|i)n
     *                   Object:  el objeto asociado al parametro
     *                   ej: (AmbienteType,Date,String,Integer).
     * @return (List object) obtenidos por el HQL y los objetos que extienden del AbstractDao.
     */
    @SuppressWarnings("unchecked")
    protected List findQueryWhere(Class clazz, String where, Map<String, Object> hashMap) {
        List objects = new ArrayList();
        try {
            startOperation();
            Query query = session.createQuery(" from " + clazz.getSimpleName() + " a " + " where " +
                    where);
            query = setQueryParameters(query, hashMap);

            System.out.println(query.getQueryString());
            if (query.list() != null) {
                objects.addAll(query.list());
            }

            tx.commit();
            if (logger.isDebugEnabled()) {
                logger.debug("findQuery: " + clazz.getSimpleName() + where +
                    "cantidad de registros: " + objects.size());
            }
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
        return objects;
    }
    /**
     * Documentacion pendiente.
     *
     * @param clazz requerido.
     * @param where requerido.
     * @param hashMap requerido.
     * @param minimo requerido.
     * @param maximo requerido.
     *
     * @return (documentacion pendiente).
     */
    @SuppressWarnings("unchecked")
    protected List findQueryToDelimit(Class clazz, String where, Map<String, Object> hashMap,
        Integer minimo, Integer maximo) {
        List objects = new ArrayList();
        try {
            startOperation();
            Query query = session.createQuery(" from " + clazz.getSimpleName() + " a " + " where " +
                    where).setFirstResult(minimo).setMaxResults(maximo);
            query = setQueryParameters(query, hashMap);

            System.out.println(query.getQueryString());
            if (query.list() != null) {
                objects.addAll(query.list());
            }

            tx.commit();
            if (logger.isDebugEnabled()) {
                logger.debug("findQuery: " + clazz.getSimpleName() + where +
                    "cantidad de registros: " + objects.size());
            }
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
        return objects;
    }

    /**
     * Documentacion pendiente.
     *
     * @param clazz requerido.
     *
     * @return (documentacion pendiente).
     */
    @SuppressWarnings("unchecked")
    protected List findAll(Class clazz) {
        List objects = new ArrayList();
        try {
            startOperation();
            Query query = session.createQuery("from " + clazz.getName());
            objects = query.list();
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
        if (logger.isDebugEnabled()) {
            logger.debug("findAll: " + "cantidad de registros: " + objects.size());
        }

        return objects;
    }
    /**
     * Documentacion pendiente.
     *
     * @param e requerido.
     *
     * @throws DataAccessLayerException si ocurre un problema.
     */
    protected void handleException(HibernateException e)
        throws DataAccessLayerException {
        HibernateFactory.rollback(tx);

        throw new DataAccessLayerException(e);
    }
    /**
     * Documentacion pendiente.
     *
     * @throws HibernateException si ocurre un problema.
     */
    protected void startOperation() throws HibernateException {
        session = HibernateFactory.openSession();
        tx = session.beginTransaction();
        if (logger.isDebugEnabled()) {
        	
            logger.debug("startOperation: begin transaction");
         
        }
    }
}
